package service

import (
	"strconv"
	"strings"
	"vrcm/src/vrcm/app/admin/models"
	"vrcm/src/vrcm/app/admin/models/likes"
	"vrcm/src/vrcm/app/admin/models/subject"
	dto "vrcm/src/vrcm/app/admin/service/dto/subject"
	"vrcm/src/vrcm/common/service"
)

type Statistics struct {
	service.Service
}

// GetStatisticsBySubject 根据条件统计答题结果
func (e *Statistics) GetStatisticsBySubject(d *dto.StatisticsFilterReq) ([]subject.AnswerRecordModel, error) {

	//获取匹配到的查询情况
	keys := e.GetFilter(d)
	if len(keys) <= 0 {
		return nil, nil
	}
	//根据活动获取所有答题
	recordModels := make([]subject.AnswerRecordModel, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.event_id,answer_record.paper_id,answer_record.subject_id,subject.subject_name,paper.paper_name,SUM( CASE WHEN answer_record.`is_right` = 1 THEN 1 ELSE 0 END ) AS correct_num,SUM( CASE WHEN answer_record.`is_right` != 1 THEN 1 ELSE 1 END ) AS total_num").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id = ? and answer_record.event_id in ? and answer_record.is_delete = ? and concat_ws('^^',answer_record.event_id,answer_record.paper_id,answer_record.subject_id) in ? and answer_record.type =1", d.TenantId, d.EventIds, 2, keys).
		Group("answer_record.event_id,answer_record.paper_id,answer_record.subject_id,subject.subject_name,paper_name").
		Find(&recordModels).
		Error
	if err != nil {
		return nil, err
	}

	return recordModels, err
}

// GetPerSubjectStatisticsByFilter  根据条件统计每道题用户答题结果
func (e *Statistics) GetPerSubjectStatisticsByFilter(d *dto.StatisticsBySubjectReq) ([]subject.PerSubjectStatistics, error) {

	//获取匹配到的查询情况
	keys := e.GetFilter(&d.StatisticsFilterReq)
	if len(keys) <= 0 {
		return nil, nil
	}
	//根据活动获取所有答题
	recordModels := make([]subject.PerSubjectStatistics, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.account,subject_id,is_right,answer").
		Where("answer_record.tenant_id = ? and answer_record.event_id in ? and answer_record.is_delete = ? and concat_ws('^^',answer_record.event_id,answer_record.paper_id,answer_record.subject_id) in ? and subject_id = ? and answer_record.type =1", d.TenantId, d.EventIds, 2, keys, d.SubjectId).
		Find(&recordModels).
		Error
	if err != nil {
		return nil, err
	}
	var count int64
	e.Orm.Model(&subject.SubjectOption{}).Where("subject_id = ?", d.SubjectId).Count(&count)
	//题目作答选项做+1处理
	for i := 0; i < len(recordModels); i++ {
		tempAnswers := make([]string, 0, 10)
		//弃权答题不做处理
		if recordModels[i].IsRight != 3 {
			answers := strings.Split(recordModels[i].Answer, models.Delimiter)
			for _, answer := range answers {
				s, _ := strconv.Atoi(answer)
				s++
				tempAnswers = append(tempAnswers, strconv.Itoa(s))
			}
		}

		recordModels[i].Answer = strings.Join(tempAnswers, models.Delimiter)
		recordModels[i].OptionNum = count
	}

	return recordModels, err
}

// GetStatisticsByAccount  根据条件统计用户答题结果
func (e *Statistics) GetStatisticsByAccount(d *dto.StatisticsFilterReq) ([]subject.AccountStatistics, error) {

	//获取匹配到的查询情况
	keys := e.GetFilter(d)
	if len(keys) <= 0 {
		return nil, nil
	}

	value := make(map[string]interface{})
	if len(d.Accounts) > 0 {
		value["account"] = d.Accounts
	}
	//根据活动获取所有答题
	recordModels := make([]subject.AccountStatistics, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("event_id,account,SUM( CASE WHEN `is_right` = 1 THEN 1 ELSE 0 END ) AS correct_num,SUM( CASE WHEN `is_right` != 1 THEN 1 ELSE 1 END ) AS total_num").
		Where("tenant_id = ? and event_id in ? and is_delete = ? and concat_ws('^^',event_id,paper_id,subject_id) in ? and type =1", d.TenantId, d.EventIds, 2, keys).
		Where(value).
		Group("event_id,account").
		Find(&recordModels).
		Error
	if err != nil {
		return nil, err
	}

	return recordModels, err
}

// GetPerStatisticsByAccount  每个用户答题情况统计
func (e *Statistics) GetPerStatisticsByAccount(d *dto.StatisticsByAccountReq) ([]subject.AnswerRecordModel, error) {

	//获取匹配到的查询情况
	keys := e.GetFilter(&d.StatisticsFilterReq)
	if len(keys) <= 0 {
		return nil, nil
	}

	value := make(map[string]interface{})
	if len(d.Accounts) > 0 {
		value["account"] = d.Accounts
	}
	//根据活动获取所有答题
	recordModels := make([]subject.AnswerRecordModel, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.account,answer_record.subject_id,subject.subject_name,answer_record.id,paper.paper_name,answer_record.answer,answer_record.is_right").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id = ? and answer_record.event_id in ? and answer_record.is_delete = ? and concat_ws('^^',answer_record.event_id,answer_record.paper_id,answer_record.subject_id) in ? and answer_record.account = ? and answer_record.type =1", d.TenantId, d.EventIds, 2, keys, d.Account).
		Where(value).
		Find(&recordModels).
		Error
	if err != nil {
		return nil, err
	}
	//取出答题id
	ids := make([]int, 0, 5)
	subjectMap := make(map[int]struct{})
	for _, v := range recordModels {
		_, ok := subjectMap[v.SubjectId]
		if !ok {
			ids = append(ids, v.SubjectId)
			subjectMap[v.SubjectId] = struct{}{}
		}
	}
	//计算题目的选项个数
	optionList := make([]subject.SubjectOptionMap, 0, 10)
	e.Orm.Model(&subject.SubjectOption{}).Select("count(1) as num, subject_id").Group("subject_id").Where("subject_id in ?", ids).Find(&optionList)
	optionMap := make(map[int]int)
	for _, v := range optionList {
		v := v
		optionMap[v.SubjectId] = v.Num

	}

	//题目作答选项做+1处理
	for i := 0; i < len(recordModels); i++ {
		tempAnswers := make([]string, 0, 10)
		//弃权答题不做处理
		if recordModels[i].IsRight != 3 {
			answers := strings.Split(recordModels[i].Answer, models.Delimiter)
			for _, answer := range answers {
				s, _ := strconv.Atoi(answer)
				s++
				tempAnswers = append(tempAnswers, strconv.Itoa(s))
			}
		}
		recordModels[i].Answer = strings.Join(tempAnswers, models.Delimiter)
		recordModels[i].OptionNum = optionMap[recordModels[i].SubjectId]
	}

	return recordModels, err
}

func (e *Statistics) GetFilter(d *dto.StatisticsFilterReq) []string {
	//活动试卷数据
	eventPapers := make([]subject.EventPaper, 0, 10)
	//题目数据
	subjects := make([]subject.Subject, 0, 10)
	//查询key
	keys := make([]string, 0, 10)
	//活动id
	eventIds := make([]string, 0, 10)
	//试卷id
	paperIds := make([]int, 0, 10)

	//根据活动获取试卷
	if len(d.EventIds) > 0 {
		e.Orm.Model(&subject.EventPaper{}).Where("event_paper.tenant_id = ? and event_paper.event_id in ? and paper.is_delete = 2", d.TenantId, d.EventIds).Joins("left join paper on paper.id = event_paper.paper_id").Find(&eventPapers)
	} else {
		return keys
		//e.Orm.Model(&models.EventPaper{}).Where("tenant_id = ? and paper.is_delete = 2", d.TenantId).Joins("left join paper on paper.id = event_paper.paper_id").Find(&eventPapers)
	}

	//eventIds去重
	tempEventMap := map[string]struct{}{}
	for _, v := range eventPapers {
		_, ok := tempEventMap[v.EventId]
		if ok {
			continue
		}
		eventIds = append(eventIds, v.EventId)
		tempEventMap[v.EventId] = struct{}{}
	}
	d.EventIds = eventIds
	//PaperId去重
	tempPaperMap := map[int]struct{}{}
	for _, v := range eventPapers {
		_, ok := tempPaperMap[v.PaperId]
		if ok {
			continue
		}
		paperIds = append(paperIds, v.PaperId)
		tempPaperMap[v.PaperId] = struct{}{}
	}

	//根据试卷获取题目
	if len(d.PaperIds) > 0 {
		e.Orm.Where("paper_id in ? and is_delete = ?", d.PaperIds, 2).Find(&subjects)
	} else {
		e.Orm.Where("paper_id in ? and is_delete = ?", paperIds, 2).Find(&subjects)
	}

	//获取匹配到的题目
	subjectsFilter := make([]subject.Subject, 0, 10)
	if len(d.SubjectIds) > 0 {
		idMap := ConvertStrSliceMap(d.SubjectIds)
		for _, v := range subjects {
			//筛选题目是否为勾选题目
			if !InMap(idMap, v.Id) {
				continue
			}
			subjectsFilter = append(subjectsFilter, v)
		}
	} else {
		subjectsFilter = subjects
	}

	//判断题目是属于哪个活动
	for _, v := range eventPapers {
		for _, s := range subjectsFilter {
			if v.PaperId == s.PaperId {
				key := v.EventId + models.Delimiter + strconv.Itoa(v.PaperId) + models.Delimiter + strconv.Itoa(s.Id)
				keys = append(keys, key)
			}
		}

	}

	return keys
}

// GetVoteStatistics 获取投票统计
func (e *Statistics) GetVoteStatistics(d *dto.VoteStatisticsReq) ([]subject.VoteStatistics, error) {

	votes := make([]subject.VoteStatistics, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.tenant_id,answer_record.event_id,answer_record.paper_id,paper.paper_name,COUNT(answer_record.account) as vote_num").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id =? and answer_record.event_id=? and answer_record.type = 2 and answer_record.is_delete = 2", d.TenantId, d.EventId).
		Group("tenant_id,event_id,paper_id").
		Find(&votes).Error

	if err != nil {
		return nil, err
	}

	return votes, nil

}

// GetVoteStatisticsDetail 获取投票统计详情
func (e *Statistics) GetVoteStatisticsDetail(d *dto.VoteStatisticsDetailReq) ([]subject.VoteStatisticsDetail, error) {

	votes := make([]subject.VoteStatisticsDetail, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.tenant_id,answer_record.event_id,answer_record.paper_id,paper.paper_name,subject.id as subject_id,subject.subject_name,answer_record.account,answer_record.create_time").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id =? and answer_record.event_id=? and answer_record.paper_id = ? and answer_record.type = 2 and answer_record.is_delete = 2 ", d.TenantId, d.EventId, d.PaperId).
		Find(&votes).Error

	if err != nil {
		return nil, err
	}

	//取出答题id
	ids := make([]int, 0, 5)
	subjectMap := make(map[int]struct{})
	for _, v := range votes {
		_, ok := subjectMap[v.SubjectId]
		if !ok {
			ids = append(ids, v.SubjectId)
			subjectMap[v.SubjectId] = struct{}{}
		}
	}
	//计算题目的选项个数
	optionList := make([]subject.SubjectOptionMap, 0, 10)
	e.Orm.Model(&subject.SubjectOption{}).Select("count(1) as num, subject_id").Group("subject_id").Where("subject_id in ?", ids).Find(&optionList)
	optionMap := make(map[int]int)
	for _, v := range optionList {
		v := v
		optionMap[v.SubjectId] = v.Num

	}

	//题目作答选项做+1处理
	for i := 0; i < len(votes); i++ {
		tempAnswers := make([]string, 0, 10)
		//弃权答题不做处理
		answers := strings.Split(votes[i].Answer, models.Delimiter)
		for _, answer := range answers {
			s, _ := strconv.Atoi(answer)
			s++
			tempAnswers = append(tempAnswers, strconv.Itoa(s))
		}

		votes[i].Answer = strings.Join(tempAnswers, models.Delimiter)
		votes[i].OptionNum = optionMap[votes[i].SubjectId]
	}
	return votes, nil
}

// GetQuestionStatistics 获取问卷统计
func (e *Statistics) GetQuestionStatistics(d *dto.QuestionStatisticsReq) ([]subject.QuestionStatistics, error) {

	questions := make([]subject.QuestionStatistics, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.tenant_id,answer_record.event_id,answer_record.paper_id,paper.paper_name,COUNT(answer_record.account) as join_num").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id =? and answer_record.event_id=? and answer_record.type = 5 and answer_record.is_delete = 2", d.TenantId, d.EventId).
		Group("tenant_id,event_id,paper_id").
		Find(&questions).Error

	if err != nil {
		return nil, err
	}

	return questions, nil

}

// GetQuestionStatisticsDetail 获取问卷统计详情
func (e *Statistics) GetQuestionStatisticsDetail(d *dto.QuestionStatisticsDetailReq) ([]subject.QuestionStatisticsDetail, error) {

	questions := make([]subject.QuestionStatisticsDetail, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.tenant_id,answer_record.event_id,answer_record.paper_id,paper.paper_name,subject.id as subject_id,subject.subject_name,answer_record.account,answer_record.create_time").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id =? and answer_record.event_id=? and answer_record.paper_id = ? and answer_record.type = 5 and answer_record.is_delete = 2 ", d.TenantId, d.EventId, d.PaperId).
		Find(&questions).Error

	if err != nil {
		return nil, err
	}

	//取出答题id
	ids := make([]int, 0, 5)
	subjectMap := make(map[int]struct{})
	for _, v := range questions {
		_, ok := subjectMap[v.SubjectId]
		if !ok {
			ids = append(ids, v.SubjectId)
			subjectMap[v.SubjectId] = struct{}{}
		}
	}
	//计算题目的选项个数
	optionList := make([]subject.SubjectOptionMap, 0, 10)
	e.Orm.Model(&subject.SubjectOption{}).Select("count(1) as num, subject_id").Group("subject_id").Where("subject_id in ?", ids).Find(&optionList)
	optionMap := make(map[int]int)
	for _, v := range optionList {
		v := v
		optionMap[v.SubjectId] = v.Num

	}

	//题目作答选项做+1处理
	for i := 0; i < len(questions); i++ {
		tempAnswers := make([]string, 0, 10)
		//弃权答题不做处理
		answers := strings.Split(questions[i].Answer, models.Delimiter)
		for _, answer := range answers {
			s, _ := strconv.Atoi(answer)
			s++
			tempAnswers = append(tempAnswers, strconv.Itoa(s))
		}

		questions[i].Answer = strings.Join(tempAnswers, models.Delimiter)
		questions[i].OptionNum = optionMap[questions[i].SubjectId]
	}
	return questions, nil
}

// GetSignInStatistics 获取签到统计
func (e *Statistics) GetSignInStatistics(d *dto.SignInStatisticsReq) ([]subject.SignInStatistics, error) {

	signINs := make([]subject.SignInStatistics, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.tenant_id,answer_record.event_id,answer_record.paper_id,paper.paper_name,SUM( CASE WHEN `is_right` = 1 THEN 1 ELSE 0 END ) AS sign_num,SUM( CASE WHEN `is_right` != 1 THEN 1 ELSE 1 END ) AS total_num").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id =? and answer_record.event_id=? and answer_record.type = 6 and answer_record.is_delete = 2", d.TenantId, d.EventId).
		Group("tenant_id,event_id,paper_id,paper.paper_name").
		Find(&signINs).Error

	if err != nil {
		return nil, err
	}

	return signINs, nil
}

// GetSignInStatisticsDetail 获取签到统计详情
func (e *Statistics) GetSignInStatisticsDetail(d *dto.SignInStatisticsDetailReq) ([]subject.SignInStatisticsDetail, error) {

	questions := make([]subject.SignInStatisticsDetail, 0, 10)
	err := e.Orm.Model(&subject.AnswerRecord{}).
		Select("answer_record.tenant_id,answer_record.event_id,answer_record.paper_id,paper.paper_name,subject.id as subject_id,subject.subject_name,answer_record.account,answer_record.create_time").
		Joins(" left join subject on subject.id = answer_record.subject_id left join paper on paper.id = answer_record.paper_id").
		Where("answer_record.tenant_id =? and answer_record.event_id=? and answer_record.paper_id = ? and answer_record.type = 6 and answer_record.is_delete = 2 ", d.TenantId, d.EventId, d.PaperId).
		Find(&questions).Error

	if err != nil {
		return nil, err
	}

	return questions, nil
}

// GetLikeStatistics 获取点赞统计
func (e *Statistics) GetLikeStatistics(d *dto.LikesStatisticsReq) (subject.LikesStatistics, error) {

	like := subject.LikesStatistics{}
	param := make(map[string]interface{})

	if len(d.TenantId) > 0 {
		param["tenant_id"] = d.TenantId
	}

	if len(d.PaperId) > 0 {
		param["round_id"] = d.PaperId
	}

	if len(d.EventId) > 0 {
		param["bind_id"] = d.EventId
	}

	startTime := d.StartTime / 1000
	endTime := d.EndTime / 1000
	err := e.Orm.Model(&likes.Likes{}).
		Select("sum(like_num) as value").
		Where("live_time  BETWEEN ? AND ?", startTime, endTime).
		Where(param).
		Find(&like).Error

	if err != nil {
		return like, err
	}

	return like, nil
}

// GetLikeStatisticsDetail 获取点赞统计详情
func (e *Statistics) GetLikeStatisticsDetail(d *dto.LikesStatisticsDetailReq) ([]subject.LikesStatisticsDetail, error) {

	data := make([]subject.LikesStatisticsDetail, 0, 10)
	param := make(map[string]interface{})

	err := e.Orm.Model(&likes.Likes{}).
		Select("sum(likes.like_num) as like_num,likes.round_id as paper_id,likes.live_time,b.live_name").
		Joins(" left join live_basic b on likes.bind_id = b.id").
		Where("likes.live_time  BETWEEN ? AND ? and likes.bind_id =? and likes.tenant_id =?", d.StartTime, d.EndTime, d.EventId, d.TenantId).
		Where(param).
		Group("likes.round_id,likes.live_time,b.live_name").
		Find(&data).Error

	if err != nil {
		return data, err
	}

	return data, nil
}

// ConvertStrSliceMap 将字符串 slice 转为 map[string]struct{}。
func ConvertStrSliceMap(sl []int) map[int]struct{} {
	set := make(map[int]struct{}, len(sl))
	for _, v := range sl {
		set[v] = struct{}{}
	}
	return set
}

// InMap 判断字符串是否在 map 中。
func InMap(m map[int]struct{}, s int) bool {
	_, ok := m[s]
	return ok
}
